import { Client, Room } from "colyseus";
import { Dispatcher } from "@colyseus/command";
import { IncomingMessage } from "http";
import { GameState } from "../Schema/GameState";
import _ from 'lodash'
import { ChangeCardStateCommand, EndCommand, GetCardCommand, OnJoinCommand, OnLeaveCommand, StartCommand } from "../Commands/Commands";
export class GameRoom extends Room<GameState> {
    maxClients = 4;
    CHANNEL = '$channel'
    dispatcher = new Dispatcher(this);

    async generateRoomId(): Promise<string> {
        const ROOM_MAX = 9999
        const curIds = await this.presence.smembers(this.CHANNEL)
        let id = _.random(ROOM_MAX).toString().padStart(4, '0')
        while (curIds.includes(id)) {
            id = _.random(ROOM_MAX).toString().padStart(4, '0')
            console.log('generate roomId again')
        }
        await this.presence.sadd(this.CHANNEL, id)
        return id
    }

    async onCreate() {
        this.setState(new GameState());

        this.roomId = await this.generateRoomId()
        console.log(`room ${this.roomId} created`);

        //结束本回合
        this.onMessage('turn', (client, message) => {
            if(!this.state.isGaming)return
            //如果有n - 1个人出局，游戏结束
            let cnt = 0
            this.state.players.forEach(player => {
                if (player.isOut) cnt++
            })
            const n = this.state.players.size
            if (cnt === n - 1) return

            //找到下一个没有出局的玩家
            let nextSessionId = ''
            do {
                this.state.cur += 1
                this.state.cur %= n
                console.log(this.state.cur)
                nextSessionId = Array.from(this.state.players.keys())[this.state.cur]
                console.log('next session', nextSessionId)
            } while (this.state.players.get(nextSessionId)?.isOut)

            //给他派发牌
            this.dispatcher.dispatch(new GetCardCommand(), {
                sessionId: nextSessionId
            })
        })

        this.onMessage('start', (client) => {
            this.lock()
            this.dispatcher.dispatch(new StartCommand())
            this.dispatcher.dispatch(new GetCardCommand(),{
                sessionId:client.sessionId
            })
        })

        this.onMessage('end', () => {
            this.unlock()
            this.dispatcher.dispatch(new EndCommand())
        })

        this.onMessage('card', (client, message) => {
            const val = Math.floor(parseInt(message) / 10)
            const color = parseInt(message) % 10
            this.dispatcher.dispatch(new ChangeCardStateCommand(), {
                sessionId: client.sessionId,
                val: val,
                color: color
            })
        })
    }

    onAuth(client: Client, options: any, request?: IncomingMessage) {
        return true
    }

    onJoin(client: Client) {
        console.log(client.id)
        this.dispatcher.dispatch(new OnJoinCommand(), {
            sessionId: client.sessionId
        })
    }

    async onLeave(client: Client, consented: boolean) {
        this.state.players.get(client.sessionId)!.connected = false

        try {
            if (consented) throw new Error('consented leave')
            await this.allowReconnection(client, 610)
            this.state.players.get(client.sessionId)!.connected = true
            console.log(`${client.sessionId} leave`)
        } catch (e) {
            this.dispatcher.dispatch(new OnLeaveCommand(), {
                sessionId: client.sessionId
            })
        }
    }

    onDispose() {
        this.dispatcher.stop()
        console.log(`room ${this.roomId} dispose`);
        this.presence.srem(this.CHANNEL, this.roomId)
    }
}